class Set {
    constructor () {
        this.items = {}
    }

    add (value) {
        if (this.has(value)) {
            return false
        }

        this.items[value] = value
        return true
    }

    remove (value) {
        if (!this.has(value)) {
            return false
        }

        delete this.items[value]
        return true
    }

    has (value) {
        return this.items.hasOwnProperty(value)
    }

    clear () {
        this.items = {}
    }

    size () {
        return Object.keys(this.items).length
    }

    values () {
        return Object.values(this.items)
    }

    union (otherSet) {
        let unionSet = new Set()
        let values = this.values()
        for (let i = 0, len = values.length; i < len; i++) {
            unionSet.add(values[i])
        }

        // otherSet
        let otherValues = otherSet.values()
        for (let i = 0, len = otherValues.length; i < len; i++) {
            unionSet.add(otherValues[i])
        }
        return unionSet
    }

    intersection (otherSet) {
        let intersection = new Set()
        let currentSetSize = this.size()
        let otherSetSize = otherSet.size()

        let shortSet = null
        let longSet = null
        if (currentSetSize > otherSetSize) {
            shortSet = otherSet
            longSet = this
        } else {
            shortSet = this
            longSet = otherSet
        }

        let values = shortSet.values()
        let count = values.length
        for (let i = 0; i < count; i++) {
            let item = values[i]
            if (longSet.has(item)) {
                intersection.add(item)
            }
        }

        return intersection
    }

    difference (otherSet) {
        let diffSet = new Set()
        let values = this.values()
        for (let i = 0, len = this.size(); i < len; i++) {
            if (!otherSet.has(values[i])) {
                diffSet.add(values[i])
            }
        }

        values = otherSet.values()
        for (let i = 0, len = otherSet.size(); i < len; i++) {
            if (!this.has(values[i])) {
                diffSet.add(values[i])
            }
        }

        return diffSet
    }

    isSubSet (subSet) {
        let values = subSet.values()
        for (let i = 0, len = values.length; i < len; i++) {
            if (!this.has(values[i])) {
                return false
            }
        }
        return true
    }
}

export default Set


